import camera from '@ohos.multimedia.camera';
import deviceInfo from '@ohos.deviceInfo';
import fileIo from '@ohos.file.fs';
import image from '@ohos.multimedia.image';
import media from '@ohos.multimedia.media';
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
import MediaModel from './MediaHelper';
import { BusinessError } from '@ohos.base';
import util from '@ohos.util';
import http from '@ohos.net.http';

const FOUR = 4; // format
const EIGHT = 8; // capacity
const FOUR_THOUSAND_AND_SIXTY_NINE = 4096; // buffer大小
let buffer = new ArrayBuffer(FOUR_THOUSAND_AND_SIXTY_NINE);

const cameraMode = {
  modePhoto: 0, // 拍照模式
  modeVideo: 1, // 录像模式
};

const cameraWH = {
  width: 480,
  height: 360,
};

/**
 * 分辨率
 */
export enum VideoFrame {
  VIDEOFRAME_1920_1080,
  VIDEOFRAME_1280_720,
  VIDEOFRAME_800_600,
};

type VideoFrameWH = {
  width: number;
  height: number;
};

const TAG = '[CameraModel]';

export default class CameraService {
  private mediaModel: MediaModel = undefined;
  private fileAsset: mediaLibrary.FileAsset = undefined;
  private cameraMgr: camera.CameraManager = undefined;
  private camerasArray: Array<camera.CameraDevice> = undefined;
  private cameraInput: camera.CameraInput = undefined;
  private previewOutput: camera.PreviewOutput = undefined;
  private photoOutPut: camera.PhotoOutput = undefined;
  private capSession: camera.CaptureSession = undefined;
  private videoOutput: camera.VideoOutput = undefined;
  private capability: camera.CameraOutputCapability = undefined;

  private avRecorder: media.AVRecorder = undefined;
  private receiver: image.ImageReceiver = undefined;
  private photoPath: string = '';
  private fd: number = -1;
  private takePictureHandle: (photoUri: string) => void = undefined;
  private currentMode:number = cameraMode.modePhoto;

  public Base64String:string = "";

  private videoFrameWH: VideoFrameWH = {
    width: 480,
    height: 360,
  }; // 视频分辨率
  private imageRotation: camera.ImageRotation = camera.ImageRotation.ROTATION_90; // 图片旋转角度

  // private videoProfile: media.VideoRecorderProfile = {
  //   audioChannels: 2,
  //   audioCodec: media.CodecMimeType.AUDIO_AAC,
  //   audioBitrate: 48000,
  //   audioSampleRate: 48000,
  //   fileFormat: media.ContainerFormatType.CFT_MPEG_4,
  //   videoBitrate: 48000,
  //   videoCodec: media.CodecMimeType.VIDEO_MPEG4,
  //   videoFrameWidth: 480,
  //   videoFrameHeight: 360,
  //   videoFrameRate: 30,
  // };
  private videoSourceType: number = 0;

  constructor() {
    this.mediaModel = MediaModel.getMediaInstance();
    this.receiver = image.createImageReceiver(
      cameraWH.width,
      cameraWH.height,
      FOUR,
      EIGHT
    );
    console.info(TAG, 'createImageReceiver');
    this.receiver.on('imageArrival', () => {
      console.info('CameraModel imageArrival');
      this.receiver.readNextImage((err, image) => {
        console.info('CameraModel readNextImage');
        if (err || image === undefined) {
          console.error('CameraModel failed to get valid image');
          return;
        }
        image.getComponent(FOUR, (errMsg, img) => {
          console.info('CameraModel getComponent');
          if (errMsg || img === undefined) {
            console.info('CameraModel failed to get valid buffer');
            return;
          }

          if (img.byteBuffer) {
            buffer = img.byteBuffer;
          } else {
            console.error('CameraModel img.byteBuffer is undefined');
          }
          //this.saveImage(buffer, image);
          this.ConvertBase64(buffer);
        });
      });
    });
  }

  /**
   * 设置分辨率
   * @param videoFrame
   */
  setVideoFrameWH(videoFrame: VideoFrame): void {
    switch (videoFrame) {
      case VideoFrame.VIDEOFRAME_800_600:
        this.videoFrameWH = {
          width: 800,
          height: 600,
        };
        console.info(
          TAG,
          `setVideoFrameWH videoFrameWH:${JSON.stringify(this.videoFrameWH)}`
        );
        break;
      case VideoFrame.VIDEOFRAME_1280_720:
        this.videoFrameWH = {
          width: 1280,
          height: 720,
        };
        console.info(
          TAG,
          `setVideoFrameWH videoFrameWH:${JSON.stringify(this.videoFrameWH)}`
        );
        break;
      case VideoFrame.VIDEOFRAME_1920_1080:
        this.videoFrameWH = {
          width: 1920,
          height: 1080,
        };
        console.info(
          TAG,
          `setVideoFrameWH videoFrameWH:${JSON.stringify(this.videoFrameWH)}`
        );
        break;
    }
  }
  /**
   * 设置图片旋转角度
   * @param imageRotation
   */
  setImageRotation(imageRotation: camera.ImageRotation): void {
    this.imageRotation = imageRotation;
  }

  /**
   * 保存图片
   * @param buffer
   * @param img
   */
  async saveImage(buffer: ArrayBuffer, img: image.Image): Promise<void> {
    console.info(TAG, 'savePicture');
    this.fileAsset = await this.mediaModel.createAndGetUri(mediaLibrary.MediaType.IMAGE);
    this.photoPath = this.fileAsset.uri;
    console.info(`CameraModel this.photoUri = ${this.photoPath}`);
    console.info(`CameraModel this.relativePath = ${this.fileAsset.relativePath}`);
    console.info(`CameraModel this.displayName = ${this.fileAsset.displayName}`);
    try {
      this.fd = await this.mediaModel.getFdPath(this.fileAsset);
      console.info(`CameraModel this.fd = ${this.fd}`);
      await fileIo.write(this.fd, buffer);
      await this.fileAsset.close(this.fd);
      await img.release();
    } catch (e) {
      console.info('CameraModel create err = '+JSON.stringify(e));
      console.info('CameraModel create err.code  = '+JSON.stringify(e.code));
    }
    console.info('CameraModel save image done');
    if (this.takePictureHandle) {
      this.takePictureHandle(this.photoPath);
    }
  }
  public reBase64() : string
  {
      return this.Base64String;
  }
  async ConvertBase64(buffer: ArrayBuffer): Promise<void> {
    let base64 = new util.Base64Helper(); // 实例化Base64Helper
    //let num = fs.readSync(fd, buf);   // 读取文件
    let data = base64.encodeSync(new Uint8Array(buffer.slice(0, buffer.byteLength))) //  转换成Uint8Array
    console.info(`data长度:${data.length}`)
    console.info(`data:${data}`)
    let textDecoder = util.TextDecoder.create('utf-8', { ignoreBOM : true })
    let retStr = textDecoder.decodeWithStream( data , {stream: false});
    console.info(`data长度:${data.length}`)
    console.info(`data:${data}`)
    this.Base64String = retStr;
    //this.UploadBase64(retStr);
  }
  public UploadBase64(Base64 :string)
  {
    try {
      let httpRequest = http.createHttp();
      httpRequest.request(
        // 填写HTTP请求的URL地址，可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
        //注意，禁止出现双斜杠，否则调用接口会出现404
        "http://recovery.zhimin.group:8880/Admin/API/UploadImages",
        {
          method: http.RequestMethod.POST, // 可选，默认为http.RequestMethod.GET
          // 开发者根据自身业务需要添加header字段
          header: {
            'Content-Type': 'application/json'
          },
          // 当使用POST请求时此字段用于传递内容
          extraData: {
            "imageData": Base64,
            //"keyword": this.PhoneUrl+ this.MachineID + "&timestamp=" + Date.now(),
          },
          // expectDataType: http.HttpDataType.STRING, // 可选，指定返回数据的类型
          // usingCache: true, // 可选，默认为true
          // priority: 1, // 可选，默认为1
          // connectTimeout: 60000, // 可选，默认为60000ms
          // readTimeout: 60000, // 可选，默认为60000ms
          // usingProtocol: http.HttpProtocol.HTTP1_1, // 可选，协议类型默认值由系统自动指定
        }, (err, data) => {
        if (!err) {
          // data.result为HTTP响应内容，可根据业务需要进行解析
          //let  obj : Person = JSON.parse(data.result) as Person;
          //this.message =obj.Data;

          //let jsonString = '{"name": "John", "age": 30, "city": "New York"}';
          //let obj2 : Persono = JSON.parse(jsonString) as Persono;

          //2024年3月13日 说明 data.result必须先要toString才能被JSON.parse解析
          let jsonString = data.result.toString();
          if(data.responseCode == 200) {
            let obj: Result = JSON.parse(jsonString) as Result;
            //console.log(obj.data); // 输出 "John"
            //this.message = obj.msg.toString();

          }
          else {
            //this.message = data.result.toString();
            //this.QRImage = obj.data.toString();
          }
          //this.FontColor = Color.Green;
          //hilog.info(0x0023, 'postres','Result:' + obj.code);
          //let  obj  = JSON.stringify(data.result);
          //this.message = obj.data.type;

          //console.info('Result:' + JSON.stringify(data.result));

          // console.info('code:' + JSON.stringify(data.responseCode));
          // data.header为HTTP响应头，可根据业务需要进行解析
          // console.info('header:' + JSON.stringify(data.header));
          // console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
          // 取消订阅HTTP响应头事件
          httpRequest.off('headersReceive');
          // 当该请求使用完毕时，调用destroy方法主动销毁
          httpRequest.destroy();
        } else {
          console.info('error:' + JSON.stringify(err));
          // 取消订阅HTTP响应头事件
          httpRequest.off('headersReceive');
          // 当该请求使用完毕时，调用destroy方法主动销毁。
          httpRequest.destroy();
        }
      });
    }
    catch (error) {
      // 在这里处理错误
      console.error("请求生成二维码时发生错误:", error);
    }
  }
  /**
   * 初始化相机
   * @param surfaceId
   */
  async initCamera(surfaceId: string,Index: number): Promise<void> {
    console.info(TAG, `initCamera surfaceId:${surfaceId}`);
    await this.cameraRelease();
    console.info(TAG, `deviceInfo.deviceType = ${deviceInfo.deviceType}`);
    if (deviceInfo.deviceType === 'default') {
      console.info(TAG, `deviceInfo.deviceType default 1 = ${deviceInfo.deviceType}`);
      this.videoSourceType = 1;
      console.info(TAG, `deviceInfo.deviceType default 2 = ${deviceInfo.deviceType}`);
    } else {
      console.info(TAG, `deviceInfo.deviceType other 1 = ${deviceInfo.deviceType}`);
      this.videoSourceType = 0;
      console.info(TAG, `deviceInfo.deviceType other 2 = ${deviceInfo.deviceType}`);
    }
    console.info(TAG, 'getCameraManager begin');
    try {
      console.info(TAG, 'getCameraManager try begin');
      this.cameraMgr = camera.getCameraManager(globalThis.cameraContext);
      console.info(TAG, 'getCameraManager try end');
    } catch (e) {
      console.info(TAG, `getCameraManager catch e:${JSON.stringify(e)}`);
      console.info(TAG, `getCameraManager catch code:${JSON.stringify(e.code)}`);
      console.info(TAG, `getCameraManager catch message:${JSON.stringify(e.message)}`);
    }
    console.info(TAG, 'getCameraManager end');
    console.info(TAG, `getCameraManager ${JSON.stringify(this.cameraMgr)}`);
    this.camerasArray = this.cameraMgr.getSupportedCameras();
    console.info(TAG, `get cameras ${this.camerasArray.length}`);
    if (this.camerasArray.length === 0) {
      console.info(TAG, 'cannot get cameras');
      return;
    }


    //这里修改摄像头
    //let mCamera = this.camerasArray[2]; //熵基
    //let mCamera = this.camerasArray[0]; //其他
    let mCamera = this.camerasArray[Index];
    this.cameraInput = this.cameraMgr.createCameraInput(mCamera);
    this.cameraInput.open();
    console.info(TAG, 'createCameraInput');
    this.capability = this.cameraMgr.getSupportedOutputCapability(mCamera);
    let previewProfile = this.capability.previewProfiles[0];
    this.previewOutput = this.cameraMgr.createPreviewOutput(
      previewProfile,
      surfaceId
    );
    console.info(TAG, 'createPreviewOutput');
    let rSurfaceId = await this.receiver.getReceivingSurfaceId();
    let photoProfile = this.capability.photoProfiles[0];
    this.photoOutPut = this.cameraMgr.createPhotoOutput(
      photoProfile,
      rSurfaceId
    );
    this.capSession = this.cameraMgr.createCaptureSession();
    console.info(TAG, 'createCaptureSession');
    this.capSession.beginConfig();
    console.info(TAG, 'beginConfig');
    this.capSession.addInput(this.cameraInput);
    this.capSession.addOutput(this.previewOutput);
    this.capSession.addOutput(this.photoOutPut);
    await this.capSession.commitConfig();
    await this.capSession.start();

    registerCaptureSessionError(this.capSession)

    console.info(TAG, 'captureSession start');
  }

  setTakePictureHandleCallback(callback): void {
    this.takePictureHandle = callback;
  }

  /**
   * 拍照
   */
  async takePicture(): Promise<void> {
    console.info(TAG, 'takePicture');
    if (this.currentMode === cameraMode.modeVideo) {
      this.currentMode = cameraMode.modePhoto;
    }
    console.info(TAG, `takePicture imageRotation:${this.imageRotation}`);
    let photoSettings = {
      rotation: this.imageRotation,
      quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM,
      location: {
        // 位置信息，经纬度
        latitude: 12.9698,
        longitude: 77.75,
        altitude: 1000,
      },
      mirror: false,
    };
    console.info(TAG, `takePicture photoSettings: ` + JSON.stringify(photoSettings));
    await this.photoOutPut.capture(photoSettings);
    console.info(TAG, 'takePicture done');
    AppStorage.Set('isRefresh', true);
  }

  // /**
  //  * 开始录像
  //  */
  // async startVideo(): Promise<void> {
  //   console.info(TAG, 'startVideo begin');
  //   console.info(TAG, 'startVideo 1');
  //   await this.capSession.stop();
  //   console.info(TAG, 'startVideo 2');
  //   this.capSession.beginConfig();
  //   console.info(TAG, 'startVideo 3');
  //   if (this.currentMode === cameraMode.modePhoto) {
  //     this.currentMode = cameraMode.modeVideo;
  //     if (this.photoOutPut) {
  //       this.capSession.removeOutput(this.photoOutPut);
  //       this.photoOutPut.release();
  //     }
  //   } else {
  //     if (this.videoOutput) {
  //       try {
  //         console.info(TAG, 'startVideo 4');
  //         this.capSession.removeOutput(this.videoOutput);
  //         console.info(TAG, 'startVideo 5');
  //       } catch (e) {
  //         console.info(TAG, `startVideo catch e:${JSON.stringify(e)}`);
  //         console.info(TAG, `startVideo catch code:${JSON.stringify(e.code)}`);
  //         console.info(TAG, `startVideo catch message:${JSON.stringify(e.message)}`);
  //       }
  //     }
  //   }
  //   if (this.videoOutput) {
  //     try {
  //       console.info(TAG, 'startVideo 6');
  //       this.capSession.removeOutput(this.videoOutput);
  //       console.info(TAG, 'startVideo 7');
  //     } catch (e) {
  //       console.info(TAG, `startVideo catch e:${JSON.stringify(e)}`);
  //       console.info(TAG, `startVideo catch code:${JSON.stringify(e.code)}`);
  //       console.info(TAG, `startVideo catch message:${JSON.stringify(e.message)}`);
  //     }
  //     try {
  //       console.info(TAG, 'startVideo release 1');
  //       await this.videoOutput.release();
  //       console.info(TAG, 'startVideo release 2');
  //     } catch (e) {
  //       console.info(TAG, `startVideo catch e:${JSON.stringify(e)}`);
  //       console.info(TAG, `startVideo catch code:${JSON.stringify(e.code)}`);
  //       console.info(TAG, `startVideo catch message:${JSON.stringify(e.message)}`);
  //     }
  //   }
  //   console.info(TAG, 'startVideo 8');
  //   this.fileAsset = await this.mediaModel.createAndGetUri(mediaLibrary.MediaType.VIDEO);
  //   console.info(TAG, `startVideo fileAsset:${this.fileAsset}`);
  //   this.fd = await this.mediaModel.getFdPath(this.fileAsset);
  //   console.info(TAG, `startVideo fd:${this.fd}`);
  //   media.createAVRecorder(async (error, recorder) => {
  //     console.info(TAG, `startVideo into createAVRecorder:${recorder}`);
  //     if (recorder != null) {
  //       console.info(TAG, `startVideo into recorder:${recorder}`);
  //       this.avRecorder = recorder;
  //       console.info(TAG, `startVideo createAVRecorder success:${this.avRecorder}`);
  //       // 当前录像配置
  //       let currConfig = {
  //         audioSourceType: 1,
  //         videoSourceType: this.videoSourceType,
  //         profile: this.videoProfile,
  //         url: `fd://${this.fd}`,
  //         rotation: 0
  //       };
  //       console.info(TAG, `startVideo into recorder:${recorder}`);
  //       await this.avRecorder.prepare(currConfig);
  //       console.info(TAG, `startVideo videoConfig:${JSON.stringify(currConfig)}`);
  //       let videoId = await this.avRecorder.getInputSurface();
  //       let videoProfile = this.capability.videoProfiles[0];
  //       console.info(TAG, `startVideo capability.videoProfiles[]=: ${JSON.stringify(this.capability.videoProfiles)}`);
  //       console.info(TAG, `startVideo videoProfile:${JSON.stringify(videoProfile)}`);
  //       this.videoOutput = this.cameraMgr.createVideoOutput(videoProfile, videoId);
  //       console.info(TAG, `startVideo videoOutput:${this.videoOutput}`);
  //       this.capSession.addOutput(this.videoOutput);
  //       console.info(TAG, 'startVideo addOutput');
  //       await this.capSession.commitConfig();
  //       console.info(TAG, 'startVideo commitConfig');
  //       await this.capSession.start();
  //       console.info(TAG, 'startVideo commitConfig capSession');
  //       await this.videoOutput.start();
  //       console.info(TAG, 'startVideo commitConfig videoOutput');
  //       try {
  //         console.info(TAG, 'startVideo avRecorder.start 1');
  //         await this.avRecorder.start();
  //         console.info(TAG, 'startVideo avRecorder.start 2');
  //       } catch (e) {
  //         console.info(TAG, `startVideo catch e:${JSON.stringify(e)}`);
  //       }
  //
  //       console.info(TAG, 'startVideo end');
  //
  //     } else {
  //       console.info(TAG, `startVideo createAVRecorder fail, error:${error}`);
  //     }
  //   });
  // }

  /**
   * 停止录像
   */
  async stopVideo(): Promise<void> {
    console.info(TAG, 'stopVideo called');
    await this.avRecorder.stop();
    await this.avRecorder.release();
    await this.videoOutput.stop();
    await this.fileAsset.close(this.fd);
  }

  /**
   * 资源释放
   */
  async cameraRelease(): Promise<void> {
    console.info(TAG, 'releaseCamera');
    if (this.cameraInput) {
      await this.cameraInput.close();
    }
    if (this.previewOutput) {
      await this.previewOutput.release();
    }
    if (this.photoOutPut) {
      await this.photoOutPut.release();
    }
    if (this.videoOutput) {
      await this.videoOutput.release();
    }
    if (this.capSession) {
      await this.capSession.release();
    }
  }
}

function registerCaptureSessionError(captureSession: camera.CaptureSession): void {
  captureSession.on('error', (error: BusinessError) => {
    console.info(`Capture session error code: ${error.code}`);
  });
}
